/**
* @file ata.h
* ATA (AT Attachment) driver header definitions.
*
* To make first version of this driver I have gotten some inspiration
* from Minirighi OS, Minix and Hale Landis (www.ata-atapi.com) drivers.
* Thanks!
*
* Copyrights 2011 Michal Saman, m.saman@designplus.cz.
* This source code is release under the Apache License 2.0.m
* http://www.apache.org/licenses/LICENSE-2.0
*/
#ifndef __ATA_H
#define	__ATA_H

#include <env.h>
#include <drivers/pci/pci.h>

extern	struct ata		_ata;

/**
 * Procedure for gives drive time to set BUSY status register.
 * So waste some time with reading Alternate Status register.
 */
#define	ATA_DELAY_400NS	{ inportb(ATA_CMD_BASE_CHANNEL_1+ATA_REG_ASR);inportb(ATA_CMD_BASE_CHANNEL_1+ATA_REG_ASR); \
		inportb(ATA_CMD_BASE_CHANNEL_1+ATA_REG_ASR);inportb(ATA_CMD_BASE_CHANNEL_1+ATA_REG_ASR); }

/* Maximum cykles to wait for device BSY = 0 */
#define ATA_MAX_STATUS_WAIT				450000

/* Maximum i/o ports count, that can use ATA channel in compatability mode. */
#define ATA_CHANNEL_MAX_CMD_PORTS		8
#define ATA_CHANNEL_MAX_CTRL_PORTS		2
#define ATA_CHANNEL_TOTAL_PORTS			ATA_CHANNEL_MAX_CMD_PORTS+ATA_CHANNEL_MAX_CTRL_PORTS

/* Maximum supported legacy ATA controllers */
#define ATA_MAX_LEGACY_CTRL				2

/* Maximum supported channels per legacy controller */
#define ATA_CHANNELS_PER_LEGACY_CTRL	2

/* Maximum supported disk devices per channel */
#define ATA_DEVICES_PER_CHANNEL			2

/* I/O ports bases */
#define ATA_CMD_BASE_CHANNEL_1			0x1F0
#define	ATA_CMD_BASE_CHANNEL_2			0x170
#define	ATA_CMD_BASE_CHANNEL_3			0x1E8
#define	ATA_CMD_BASE_CHANNEL_4			0x168

#define ATA_CTRL_BASE_CHANNEL_1			0x3F0
#define	ATA_CTRL_BASE_CHANNEL_2			0x370
#define	ATA_CTRL_BASE_CHANNEL_3			0x3E8
#define	ATA_CTRL_BASE_CHANNEL_4			0x368

/* Default legacy IRQ assigments */
#define	ATA_CHANNEL1_IRQ				14
#define	ATA_CHANNEL2_IRQ				15
#define	ATA_CHANNEL3_IRQ				12
#define	ATA_CHANNEL4_IRQ				10

/* Type of ATA Device connected to channel */
#define	ATA_DEV_NONE					0			/*<< No device connected */
#define	ATA_DEV_UNKNOWN					1			/*<< Connected unknown device */
#define	ATA_DEV_PATA					2			/*<< Connected parallel ATA device */
#define	ATA_DEV_PATAPI					3			/*<< Connected parallel ATAPI device */
#define	ATA_DEV_SATA					4			/*<< Connected serial ATA device */
#define	ATA_DEV_SATAPI					5			/*<< Connected serial ATAPI device */


/* Channel compatability mode mask */
#define ATA_CHANNEL1_COMP_MASK				0x1
#define ATA_CHANNEL2_COMP_MASK				0x4

/* I/O controllers base port structure */
typedef struct ata_base {
	uint16_t	cmd_base;
	uint16_t	ctrl_base;
} ata_base_t;

/* Command register offset port (offset agains cmd_bas) */
#define		ATA_REG_DATA_OFFSET				0			/*<< r/w Data register */
#define		ATA_REG_ERR_OFFSET				1			/*<< r 	 Error register, w Feature register */
#define		ATA_REG_SC_OFFSET				2			/*<< r/w Sector Count register */
#define		ATA_REG_SN_OFFSET				3			/*<< r/w Sector Number (LBA [7:0]) */
#define		ATA_REG_CL_OFFSET				4			/*<< r/w Cylinder Low byte [15:8]) */
#define		ATA_REG_CH_OFFSET				5			/*<< r/w Cylinder High byte (LBA [23:16]) */
#define		ATA_REG_DH_OFFSET				6			/*<< r/w Device/head register (LBA [27:24]) */
#define		ATA_REG_SR_CMD_OFFSET			7			/*<< r	 Status register, w Command register */

#define		ATA_REG_ASR_DEVC_OFFSET			6			/*<< r	Alternate status register, w Device control register */
#define		ATA_REG_ADDR_OFFSET				7			/*<< Device addres (obsolve register) */

/* Command register index in ata_channel.io_ports */
#define 	ATA_REG_DATA					0			/*<< Data register */
#define		ATA_REG_ERR						1			/*<< Error register */
#define		ATA_REG_FEAT					1			/*<< Features register */
#define		ATA_REG_SC						2			/*<< Sector Count register */
#define		ATA_REG_SN						3			/*<< Sector Number register */
#define		ATA_REG_CL						4			/*<< Cylinder Low register */
#define		ATA_REG_CH						5			/*<< Cylinder High register */
#define 	ATA_REG_DH						6			/*<< Device / Head register */
#define		ATA_REG_SR						7			/*<< Status register */
#define		ATA_REG_CMD						7			/*<< Command register */

#define		ATA_REG_ASR						8			/*<< Alternate status register */
#define		ATA_REG_DEVC					8			/*<< Device Controll register */
#define		ATA_REG_ADDR					9			/*<< Address Register */

/* ************************************
 * Register value MASKs
 * ************************************
 */

/* Device / head register values */
#define 	ATA_REG_DH_OBSOLETE				0xA0		/*<< This want's ATA-1 to ATA-3, bits 7 and 5 must be set to 1 */
#define 	ATA_REG_DH_LBA_MODE				0x40		/*<< Bit 6 is representing address mode 1 - LBA, 0 - CHS */

/* Device control register values (WRITE) */
#define		ATA_REG_DEVC_HD15				0x08		/*<< Bit 4 = 1, this is for old ATA compatability */
#define		ATA_REG_DEVC_SRST				0x04		/*<< Bit 2 - soft reset */
#define		ATA_REG_DEVC_NIEN				0x02		/*<< Bit 1 : 0 = enable, 1 = disable interrupts */

/* Status register values */
#define		ATA_REG_SR_BSY					0x80		/*< Bit 7 : 1 = device busy, don't write command regs, 0 = you can write command regs. */
#define		ATA_REG_SR_DRDY					0x40		/*< Bit 6 : 1 = device ready, you can do any command, 0 = device not ready, only Exec. device diag. and Init. Device Params can be performed */
#define		ATA_REG_SR_DF					0x20		/*< Bit 5 : 1 = Device fault */
#define		ATA_REG_SR_DSC					0x10		/*< Bit 4 : 1 = Device seek complete */
#define		ATA_REG_SR_DRQ					0x08		/*< Bit 3 : 1 = data request, device is ready for data exchange */
#define		ATA_REG_SR_CORR					0x04		/*< Bit 2 : 1 = corrected data error */
#define		ATA_REG_SR_IDX					0x02		/*< Bit 1 : Vendor specific */
#define		ATA_REG_SR_ERR					0x01		/*< Bit 0 : 1 = Error executing last command - check error register */

/* Command register */
#define		ATA_CMD_IDENTIFY_DEVICE			0xEC		/*<< Identify device command */
#define		ATA_CMD_IDENTIFY_PACKET_DEVICE	0xA1		/*<< Identify packet device command */
#define		ATA_READ_MULTIPLE_EXT			0x29
#define		ATA_READ_MULTIPLE				0xC4
#define		ATA_WRITE_MULTIPLE_EXT			0x39
#define		ATA_WRITE_MULTIPLE				0xC5

/* ************************************
 * Addressing modes
 * ************************************
 */

/* Addresable modes */
#define		ATA_CHS							0x1
#define 	ATA_LBA_28						0x2
#define		ATA_LBA_48						0x3

/* Maximum sectors that we can read/write in one command */
#define		ATA_SC_MAX_LBA48				65536
#define		ATA_SC_MAX						256

/* ************************************
 * Main data structures
 * ************************************
 */

/* Detail information about ATA disk device. */
typedef struct ata_device_info {
	bool		is_ata;
	bool		is_removable;
	uint16_t	logical_cylinders;
	uint16_t	logical_head;
	uint16_t	logical_sectors_per_track;
	char		model_name[41];
	char		serial_number[21];
	char		firmaware_rev[9];
	uint16_t	cur_logical_cylinders;
	uint16_t	cur_logical_head;
	uint16_t	cur_logical_sectors_per_track;
	uint8_t		max_multi_sec_per_block;
	bool		stanby_timer_support;
	bool		IORDY_support;
	bool		IORDY_disabled;
	uint8_t		pio_mode;
	uint32_t	capacity_chs;
	uint8_t		cur_multi_sec_per_intrr;
	uint8_t		valid_multi_sec_per_intrr;
	uint32_t	capacity_lba28;
	uint8_t		multi_dma_support;
	uint8_t		multi_dma_selected;
	uint8_t		highest_ata_support;
	uint8_t		highest_udma_support;
	uint8_t		udma_selected;
	bool		smart_support;
	bool		smart_enabled;
	uint64_t	capacity_lba48;
	uint64_t	max_addr_capacity;
	uint8_t		addr_mode;
} ata_device_info_t;

/* Identify device structure defined by ATA specification.
 * Result of IDENTIFY commad.
 */
typedef struct ata_identify_data {
	uint16_t	gen_conf;						/* w0 */
	uint16_t	logical_cylinders;				/* w1 */
	uint16_t	_res;							/* w2 */
	uint16_t	logical_head;					/* w3 */
	uint16_t	_ret1;							/* w4 */
	uint16_t	_ret2;							/* w5 */
	uint16_t	logical_sectors_per_track;		/* w6 */
	uint16_t	_ret3;							/* w7 */
	uint16_t	_ret4;							/* w8 */
	uint16_t	_ret5;							/* w9 */
	uint16_t	serial_number[10];				/* w10-19 */
	uint16_t	_ret6;							/* w20 */
	uint16_t	_ret7;							/* w21 */
	uint16_t	_obs1;							/* w22 */
	uint16_t	firmware_ver[4];				/* w23-26 */
	uint16_t	model_name[20];					/* w27-46 */
	uint16_t	max_rw_multiple;				/* w47 */
	uint16_t	_ret8;							/* w48 */
	uint16_t	caps1;							/* w49 */
	uint16_t	caps2;							/* w50 */
	uint16_t	pio_data_mode_num;				/* w51 */
	uint16_t	_ret9;							/* w52 */
	uint16_t	validity;						/* w53 */
	uint16_t	cur_logical_cylinders;			/* w54 */
	uint16_t	cur_logical_head;				/* w55 */
	uint16_t	cur_logical_sectors_per_track;	/* w56 */
	uint16_t	cur_sec_cap_h;					/* w57 */
	uint16_t	cur_sec_cap_l;					/* w58 */
	uint16_t	cur_rw_multiple;				/* w59 */
	uint16_t	total_lba28_sec_h;				/* w60 */
	uint16_t	total_lba28_sec_l;				/* w61 */
	uint16_t	ret10;							/* w62 */
	uint16_t	mw_dma_mode;					/* w63 */
	uint16_t	adv_pio_modes;					/* w64 */
	uint16_t	mw_dma_min_cycle;				/* w65 */
	uint16_t	mw_dma_rec_cycle;				/* w66 */
	uint16_t	pio_min_raw_cycle;				/* w67 */
	uint16_t	pio_min_iordy_cycle;			/* w68 */
	uint16_t	_res2;							/* w69 */
	uint16_t	_res3;							/* w70 */
	uint16_t	_res4;							/* w71 */
	uint16_t	_res5;							/* w72 */
	uint16_t	_res6;							/* w73 */
	uint16_t	_res7;							/* w74 */
	uint16_t	quote_depth;					/* w75 */
	uint16_t	_res8;							/* w76 */
	uint16_t	_res9;							/* w77 */
	uint16_t	_res10;							/* w78 */
	uint16_t	_res11;							/* w79 */
	uint16_t	ata_version_major; 				/* w80 */
	uint16_t	ata_version_minor; 				/* w81 */
	uint16_t	com_set0;	 					/* w82 */
	uint16_t	com_set1;	 					/* w83 */
	uint16_t	com_set_sup; 					/* w84 */
	uint16_t	com_set_enb1; 					/* w85 */
	uint16_t	com_set_enb2; 					/* w86 */
	uint16_t	com_set_def; 					/* w87 */
	uint16_t	udma;		 					/* w88 */
	uint16_t	_res12[1 + 99 - 89]	;			/* w89 - 99 */
	uint16_t 	total_lba48_sec_0;
	uint16_t 	total_lba48_sec_1;
	uint16_t 	total_lba48_sec_2;
	uint16_t 	total_lba48_sec_3;
	uint16_t 	_res13[1 + 127 - 104];
	uint16_t 	_vs1[1 + 159 - 128];
	uint16_t 	_res14[1 + 255 - 160];
} ata_identify_data_t;

/* Size of INDENTIFY result data structure (in words) */
#define	ATA_INDETIFY_SIZE		256

/* Macros for parsing identify_structure */
#define		GETBITB(in_byte, n)	( ((uint8_t) in_byte >> n) & 0x01)
#define		GETBITW(in_word, n)	( ((uint16_t) in_word >> n) & 0x0001)
#define		GETBITDW(in_dword, n)	( ((uint32_t) in_dword >> n) & 0x00000001)

#define		GETBYTEW(in_word, n)	( ((uint16_t) in_word >> (n<<3)) & 0x00FF )
#define		SWAPW(in_word)	( (GETBYTEW(in_word,0)<<8) | (GETBYTEW(in_word,1)) )
#define 	MAKEDW(in_word1,in_word0) ( (((uint32_t) in_word1 << 16) | (uint16_t) in_word0) )
#define 	MAKEQW(in_word3,in_word2,in_word1,in_word0) ( (((uint64_t) in_word2 << 48 | (uint64_t) in_word2 << 32 | (uint32_t) in_word1 << 16) | (uint16_t) in_word0) )

/* Definition of ATA disk device. */
typedef struct ata_device {
	uint16_t				device_type;			/*<< See ATA_DEV_* definitions */
	uint8_t					dh_reg;					/*<< Device / Head register value for device */
	ata_device_info_t		device_info;			/*<< Structured device information */
	ata_identify_data_t		raw_idata;				/*<< Raw data returned by IDENTIFY command */
	uint8_t					channel_position;		/*<< 0 - master, 1 - slave */
	struct ata_channel *	device_channel;			/*<< link to device channel */
} ata_device_t ;

/* Definition of ATA channel */
typedef struct ata_channel {
	ata_device_t			devices[ATA_CHANNELS_PER_LEGACY_CTRL];
	uint16_t				cmd_base;
	uint16_t				ctrl_base;
	uint16_t				io_ports[ATA_CHANNEL_TOTAL_PORTS];
	uint16_t				irq;
} ata_channel_t;

/* Definition of ATA controller */
typedef struct  ata_controller {
        ata_channel_t		    channels[ATA_CHANNELS_PER_LEGACY_CTRL];
        uint32_t                device_id;
        uint32_t                vendor_id;
        pci_conf_space_t *      pci_conf_space;
} ata_controller_t;

struct ata {
	ata_controller_t *			ata_ctrls;
	size_t						count;
};

/* Command structure used for read / write operations */
typedef struct ata_rw_cmd {
	uint8_t		sc;				/*<< Sector count */
	uint8_t		sn;				/*<< Sector number - S - LBA_LOW*/
	uint8_t		cl;				/*<< Sector cylinder (low) - C - LBA_MID */
	uint8_t		ch;				/*<< Sector cylinder (hign)- C - LBA_MID */
	uint8_t		dh;				/*<< Device / head - H - LBA_HIGH */
} ata_rw_cmd_t;

/* Structure for different addresing modes: CHS, LBA28, LBA48 */
typedef struct block_addr {
	union {
		/* CHS addresing */
		struct {
			uint8_t	sn;
			uint8_t	cl;
			uint8_t ch;
		};
		/* LBA-28, LBA-48 addresing */
		struct {
			uint8_t lba_low;		/*<< sn */
			uint8_t lba_low1;
			uint8_t lba_mid;		/*<< cl */
			uint8_t lba_mid1;
			uint8_t lba_high;		/*<< ch */
			uint8_t lba_high1;
		};
	};
	/* DeviceHead */
	uint8_t dh;
} block_addr_t;

extern void ata_controllers_detect();
extern int ata_device_detect(bool use_interrupt);
extern void ata_init();
extern int ata_cmd_read(ata_device_t * dev, uint64_t lba, size_t count, uint16_t * buffer);
extern int ata_cmd_write(ata_device_t * dev, uint64_t lba, size_t count, uint16_t * buffer);
extern void ata_show_info();
extern void ata_rw_test(int dev);

PRIVATE int ata_soft_reset(ata_channel_t * channel, bool use_interrupt);
PRIVATE int ata_trans_lba(ata_device_t * dev, uint64_t lba, block_addr_t * ba);
PRIVATE int select_device(int device_index, ata_channel_t * channel, uint8_t dh_modify);
PRIVATE void ata_fill_addr_regs(ata_device_t * dev, block_addr_t * ba, uint16_t sc);
PRIVATE void ata_process_indentify_data(int device_index, ata_channel_t * channel);
PRIVATE void ata_irq_handler_c1_ch1();
PRIVATE void ata_irq_handler_c1_ch2();
PRIVATE void ata_irq_handler_c2_ch1();
PRIVATE void ata_irq_handler_c2_ch2();
PRIVATE void __attribute__ ((cdecl)) ata_irq_c1_ch1();
PRIVATE void __attribute__ ((cdecl)) ata_irq_c1_ch2();
PRIVATE void __attribute__ ((cdecl)) ata_irq_c2_ch1();
PRIVATE void __attribute__ ((cdecl)) ata_irq_c2_ch2();

#endif
